﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Word_Mojo
{
    /// <summary>
    /// PlayersGameTilesDecider provides meathods for generating 7 valid letters for the player 
    /// to use in each play.  The seven letters are randomly generated and checked to ensure that 
    /// at least one valid play on the board can be made using said letters.
    /// </summary>
    class PlayersGameTilesDecider
    {
        #region Private Data Members

        //stores all the letters based on popularity
        private string[] letterPool;

        //this String array is for storing the players Tile letter values
        private List<string> playableLetters;

        private List<string> wordSuggestions;

        #endregion

        #region Construction

        /// <summary>
        /// Populates a string array of single-char letters to be randomly picked from when generating 
        /// the user's letters.  Several letters are duplicated in the "pool" so as to ensure that the 
        /// more-commonly-used letters (e.g. "A", "E") are picked more often.  
        /// </summary>
        public PlayersGameTilesDecider()
        {
            this.populateLetters();
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Returns a list of valid letters to be used on the first play of the game.  Does not do any 
        /// checking for valid plays on the board using the letters (the board is empty).  
        /// </summary>
        /// <returns>A list of single-char strings representing the player's first useable letters</returns>
        public List<String> getSevenLettersForPlayersTiles()
        {
            //return new List<string>(new String[] {"a", "b", "n", "c", "t", "s", "s"});

            while (true)
            {
                List<string> randomLetters = getRandomLetters();

                if (areValidLetters(randomLetters))
                {
                    playableLetters = randomLetters;
                    return randomLetters;
                }
            }
        }

        /// <summary>
        /// Returns a list of valid letters to be used at any point during the game.  This method checks the 
        /// randomly generated letters to ensure that at least one word can be validly-placed on the game 
        /// board.  
        /// </summary>
        /// <param name="startsWithTiles">*** For Garrett ***</param>
        /// <param name="endsWithTiles">*** For Garrett ***</param>
        /// <returns></returns>
        public List<String> getSevenLettersForPlayersTiles(List<String> playableLetters)
        {
            List<string> randomLetters = getRandomLetters();


            return null;
        }

        #endregion

        #region Private Helper Methods

        /// <summary>
        /// Polulate the array of letters based on the popularity of the letter
        /// </summary>
        private void populateLetters()
        {
            this.letterPool = new string[60] 
            { 
                "a", "a", "a", "a", "a", 
                "b", "b", 
                "c", "c", 
                "d", "d", 
                "e", "e", "e", "e", "e", 
                "f", "f", 
                "g", "g",
                "h", "h", 
                "i", "i", "i",
                "j", "j", 
                "k", "k", 
                "l", "l", 
                "m", "m", 
                "n", "n",
                "o", "o", "o", 
                "p", "p", 
                "q", "q", 
                "r", "r", 
                "s", "s", 
                "t", "t", 
                "u", "u", "u",
                "v", "v", 
                "x", "x", 
                "y", "y", "y",
                "z", "z" 
            };
        }

        /// <summary>
        /// Returns a boolean indicating if the list of randomly-generated letters are valid to 
        /// be used on the first-play.  Checks that at least one english dictionary word of valid 
        /// length can be spelled from the generated letters.
        /// </summary>
        /// <param name="inputLetters">List of randomly-generated single-char strings</param>
        /// <returns>True if letters are valid, false otherwise</returns>
        private bool areValidLetters(List<string> inputLetters)
        {
            string randomString = getStringFromRandomLetterList(inputLetters);
            List<string> combinationStrings = performCombinations(randomString, 0);
            List<string> prunedStrings = pruneCombinations(combinationStrings);

            return (prunedStrings.Count > 0);
        }

        /// <summary>
        /// Converts the list of single-char strings into a single string for passing to the 
        /// performCombinations method.  The method appends each letter in the list to a StringBuilder
        /// </summary>
        /// <param name="randomLetters">The list of seven randomly-generated letters</param>
        /// <returns>A string representing the concatenation of randomLetter's elements</returns>
        private string getStringFromRandomLetterList(List<string> randomLetters)
        {
            StringBuilder sBuilder = new StringBuilder();

            foreach (string letter in randomLetters)
            {
                sBuilder.Append(letter);
            }

            return sBuilder.ToString();
        }

        /// <summary>
        /// Iterates through the collection of string combinations created from performCombinations.  
        /// "Weeds out" the strings that aren't contained in the dictionary and/or have an invalid 
        /// length to be used in the game.
        /// </summary>
        /// <param name="combStrings">A list of all string combinations</param>
        /// <returns>A subset of combStrings that are valid words playable in the game</returns>
        private List<string> pruneCombinations(List<string> combStrings)
        {
            List<string> returnStrings = new List<string>();

            foreach (string s in combStrings)
            {
                if (!EnglishDictionary.IsInDictionary(s) ||
                    s.Length < 3 ||
                    s.Length > 6)
                {
                    continue;
                }
                else
                {
                    returnStrings.Add(s);
                }
            }

            return returnStrings;
        }

        /// <summary>
        /// Recursive implementation for getting all string combinations from a given input.  The input 
        /// is the 7-letter string generated from getRandomLetters().  This method will be used both for 
        /// generating valid letters to the player and for "helping" the player when they need a word 
        /// suggestion from their letters.
        /// </summary>
        /// <param name="index">The current index in the inputString</param>
        /// <param name="inputString">The 7-length randomly-generated string</param>
        private List<string> performCombinations(string inputString, int index)
        {
            // If inputString length is 0, throw argument exception
            if (inputString.Length == 0)
            {
                throw new ArgumentException("The input string has a length of 0.");
            }

            List<string> stringCombinations = new List<string>();

            // If inputString length is 1, return the list only containing the inputString.
            if ((inputString.Length - 1) == index)
            {
                stringCombinations.Add(inputString.Substring(index));
            }
            else
            {
                List<string> tempStrings = performCombinations(inputString, (index + 1));
                foreach (string s in tempStrings)
                {
                    stringCombinations.Add(s);
                    stringCombinations.Add(inputString[index].ToString() + s);
                }
                stringCombinations.Add(inputString[index].ToString());
            }
            return stringCombinations;
        }

        /// <summary>
        /// Generates seven random single-char letter strings from the letters array to be 
        /// given to the player.  Some letters are duplicated in the array to, hopefully, provide 
        /// an even distribution of random letters.
        /// </summary>
        /// <returns>A list of randomly-selected letters</returns>
        private List<string> getRandomLetters()
        {
            List<string> randomLetters = new List<string>();
            Random rand = new Random();

            for (int i = 0; i < 7; i++)
            {
                int randomIndex = rand.Next(60);
                randomLetters.Add(this.letterPool[randomIndex]);
            }

            return randomLetters;
        }

        #endregion
    }
}
